#ifndef DECLARATION_C__
#define DECLARATION_C__

#include <stdlib.h>
#include "basic.h"
#include "expression.h"
#include "statement-header.h"
#include "type.h"

#if 0
import std.lib;
import basic;
import expression;
import statement-base;
import type;
#endif

struct EnumDeclaration;
struct FunctionDeclaration;
struct StructDeclaration;
struct UnionDeclaration;
struct VariableDeclaration;
struct VariableDeclarationList;

struct EnumDeclaration
{
	struct Name* name;
	struct NameList* nameList;
};

struct EnumDeclaration* allocateEnumDeclaration(
	struct Name* name,
	struct NameList* nameList)
{
	struct EnumDeclaration* r = malloc(sizeof(struct EnumDeclaration));
	r->name = name;
	r->nameList = nameList;
	return r;
}

void freeEnumDeclaration(struct EnumDeclaration* f)
{
	if(f == NULL) return;
	freeName(f->name);
	freeNameList(f->nameList);
	free(f);
}

struct ArgumentDeclaration
{
	struct Type* type;
	struct Name* name;
};

struct ArgumentDeclaration* allocateArgumentDeclaration(
	struct Type* type,
	struct Name* name)
{
	struct ArgumentDeclaration* r = malloc(sizeof(struct ArgumentDeclaration));
	r->type = type;
	r->name = name;
	return r;
}

void freeArgumentDeclaration(struct ArgumentDeclaration* f)
{
	if(f == NULL) return;
	freeType(f->type);
	freeName(f->name);
	free(f);
}

struct ArgumentDeclarationList
{
	struct ArgumentDeclaration* head;
	struct ArgumentDeclarationList* tail;
};

struct ArgumentDeclarationList* allocateArgumentDeclarationList(
	struct ArgumentDeclaration* head, struct ArgumentDeclarationList* tail)
{
	assert(head != NULL);

	struct ArgumentDeclarationList* r =
		malloc(sizeof(struct ArgumentDeclarationList));
	r->head = head;
	r->tail = tail;
	return r;
};

void freeArgumentDeclarationList(struct ArgumentDeclarationList* f)
{
	if(f == NULL) return;
	freeArgumentDeclaration(f->head);
	freeArgumentDeclarationList(f->tail);
	free(f);
}

struct FunctionDeclaration
{
	struct Type* type;
	struct Name* name;
	struct ArgumentDeclarationList* arguments;
	struct Statement* statement;
};

struct FunctionDeclaration* allocateFunctionDeclaration(
	struct Type* type,
	struct Name* name,
	struct ArgumentDeclarationList* arguments,
	struct Statement* statement)
{
	struct FunctionDeclaration* r = malloc(sizeof(struct FunctionDeclaration));
	r->type = type;
	r->name = name;
	r->arguments = arguments;
	r->statement = statement;
	return r;
}

void freeFunctionDeclaration(struct FunctionDeclaration* f)
{
	if(f == NULL) return;
	freeType(f->type);
	freeName(f->name);
	freeArgumentDeclarationList(f->arguments);
	freeStatement(f->statement);
	free(f);
}

struct VariableDeclaration
{
	struct Type* type;
	struct Name* name;
	struct Expression* initialization;
};

struct VariableDeclaration* allocateVariableDeclaration(
	struct Type* type,
	struct Name* name,
	struct Expression* initialization)
{
	struct VariableDeclaration* r = malloc(sizeof(struct VariableDeclaration));
	r->type = type;
	r->name = name;
	r->initialization = initialization;
	return r;
}

void freeVariableDeclaration(struct VariableDeclaration* f)
{
	if(f == NULL) return;
	freeType(f->type);
	freeName(f->name);
	freeExpression(f->initialization);
	free(f);
}

struct VariableDeclarationList
{
	struct VariableDeclaration* head;
	struct VariableDeclarationList* tail;
};

struct VariableDeclarationList* allocateVariableDeclarationList(
	struct VariableDeclaration* head,
	struct VariableDeclarationList* tail)
{
	assert(head != NULL);

	struct VariableDeclarationList* r
		= malloc(sizeof(struct VariableDeclarationList));
	r->head = head;
	r->tail = tail;
	return r;
}

void freeVariableDeclarationList(struct VariableDeclarationList* f)
{
	if(f == NULL) return;
	freeVariableDeclaration(f->head);
	freeVariableDeclarationList(f->tail);
	free(f);
}

struct StructDeclaration
{
	struct Name* name;
	struct VariableDeclarationList* list;
};

struct StructDeclaration* allocateStructDeclaration(
	struct Name* name,
	struct VariableDeclarationList* list)
{
	struct StructDeclaration* r = malloc(sizeof(struct StructDeclaration));
	r->name = name;
	r->list = list;
	return r;
}

void freeStructDeclaration(struct StructDeclaration* f)
{
	if(f == NULL) return;
	freeName(f->name);
	freeVariableDeclarationList(f->list);
	free(f);
}

struct UnionDeclaration
{
	struct Name* name;
	struct VariableDeclarationList* list;
};

struct UnionDeclaration* allocateUnionDeclaration(
	struct Name* name,
	struct VariableDeclarationList* list)
{
	struct UnionDeclaration* r = malloc(sizeof(struct UnionDeclaration));
	r->name = name;
	r->list = list;
	return r;
}

void freeUnionDeclaration(struct UnionDeclaration* f)
{
	if(f == NULL) return;
	freeName(f->name);
	freeVariableDeclarationList(f->list);
	free(f);
}

enum DeclarationTag
{
	ENUM_DECLARATION,
	FUNCTION_DECLARATION,
	STRUCT_DECLARATION,
	UNION_DECLARATION,
	VARIABLE_DECLARATION
};

struct Declaration
{
	enum DeclarationTag tag;
	void* declaration;
};

struct Declaration* allocateDeclaration(
	enum DeclarationTag tag,
	void* declaration)
{
	struct Declaration* r = malloc(sizeof(struct Declaration));
	r->tag = tag;
	r->declaration = declaration;
	return r;
}

void freeDeclaration(struct Declaration* f)
{
	if(f == NULL) return;

	switch(f->tag)
	{
		case ENUM_DECLARATION:
			freeEnumDeclaration(f->declaration);
			break;
		case FUNCTION_DECLARATION:
			freeFunctionDeclaration(f->declaration);
			break;
		case STRUCT_DECLARATION:
			freeStructDeclaration(f->declaration);
			break;
		case UNION_DECLARATION:
			freeUnionDeclaration(f->declaration);
			break;
		case VARIABLE_DECLARATION:
			freeVariableDeclaration(f->declaration);
			break;
	}

	free(f);
}

struct DeclarationList
{
	struct Declaration* head;
	struct DeclarationList* tail;
};

struct DeclarationList* allocateDeclarationList(
	struct Declaration* head,
	struct DeclarationList* tail)
{
	struct DeclarationList* r = malloc(sizeof(struct DeclarationList));
	r->head = head;
	r->tail = tail;
	return r;
}

void freeDeclarationList(struct DeclarationList* f)
{
	if(f == NULL) return;
	freeDeclaration(f->head);
	freeDeclarationList(f->tail);
	free(f);
}

#endif
